package com.sqfw.project.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class HttpClientUtils {

    private static final String DEFAULT_CHARSET = "UTF-8";

    private static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 90000;

    private static final int DEFAULT_CONNECT_TIMEOUT = 90000;

    private static final int DEFAULT_SOCKET_TIMEOUT = 30000;

    private static final String JSON_CONTENT_TYPE = "application/json";

    private static CloseableHttpClient httpClient;

    static {
        RequestConfig config = RequestConfig.custom()
                .setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)
                .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT)
                .setSocketTimeout(DEFAULT_SOCKET_TIMEOUT).build();
        httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
    }

    /**
     * 发送Http Get请求
     *
     * @param url    请求路径
     * @param params 请求参数
     * @return
     */
    public static String get(String url, Map<String, String> params) {
        return get(url, params, DEFAULT_CHARSET);
    }

    /**
     * 发送Http Post请求
     *
     * @param url    请求路径
     * @param params 请求参数
     * @return
     */
    public static String post(String url, Map<String, String> params) {
        return post(url, params, DEFAULT_CHARSET);
    }

    /**
     * 发送Http Get请求
     *
     * @param url     请求路径
     * @param params  请求参数
     * @param charset 字符集
     * @return
     */
    public static String get(String url, Map<String, String> params, String charset) {
        if (params != null && !params.isEmpty()) {
            List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String value = entry.getValue();
                if (value != null) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
            try {
                if (url.indexOf('?') != -1) {
                    url += "&";
                } else {
                    url += "?";
                }
                url += EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
            } catch (Exception e) {
            }
        }
        log.info(url);
        HttpGet method = new HttpGet(url);
        return execute(method, charset);
    }

    /**
     * 发送Http Post请求
     *
     * @param url     请求路径
     * @param params  请求参数
     * @param charset 字符集
     * @return
     */
    public static String post(String url, Map<String, String> params, String charset) {
        List<NameValuePair> pairs = null;
        if (params != null && !params.isEmpty()) {
            pairs = new ArrayList<NameValuePair>(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String value = entry.getValue();
                if (value != null) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
        }
        log.info(url);
        HttpPost method = new HttpPost(url);
        if (pairs != null && pairs.size() > 0) {
            try {
                method.setHeader("Content-Type", "application/json;charset=utf-8");
                method.setEntity(new UrlEncodedFormEntity(pairs, charset));
            } catch (UnsupportedEncodingException e) {
            }
        }
        return execute(method, charset);
    }

    /**
     * 发送Http Post from表单请求
     *
     * @param url     请求路径
     * @param params  请求参数
     * @param charset 字符集
     * @return
     */
    public static String postForm(String url, Map<String, String> params, Map<String, String> headerParam, String charset) {
        List<NameValuePair> pairs = null;
        if (params != null && !params.isEmpty()) {
            pairs = new ArrayList<>(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                String value = entry.getValue();
                if (value != null) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), value));
                }
            }
        }
        log.info(url);
        HttpPost method = new HttpPost(url);
        if (!CollectionUtils.isEmpty(pairs)) {
            try {
                method.setHeader("Content-Type", "application/x-www-form-urlencoded");
                if (null != headerParam) {
                    for (String key : headerParam.keySet()) {
                        method.setHeader(key, headerParam.get(key));
                    }
                }
                charset = StringUtils.isEmpty(charset) ? DEFAULT_CHARSET : charset;
                method.setEntity(new UrlEncodedFormEntity(pairs, charset));
            } catch (UnsupportedEncodingException e) {
            }
        }
        return execute(method, charset);
    }

    public static String postForm(String url, Map<String, String> params, String charset) {
        return postForm(url, params, null, charset);
    }


    /**
     * 以json作为参数发送Http Post请求
     *
     * @param url    请求路径
     * @param params 请求参数
     * @return
     */
    public static String postJson(String url, Map<String, String> headerParam, Map<String, String> params) {
        return postJson(url, headerParam, params, DEFAULT_CHARSET);
    }

    public static String postJson(String url, Map<String, String> params) {
        return postJson(url, null, params, DEFAULT_CHARSET);
    }

    /**
     * 以json作为参数发送Http Post请求
     *
     * @param url     请求路径
     * @param params  请求参数
     * @param charset 字符集
     * @return
     */
    public static String postJson(String url, Map<String, String> headerParam, Map<String, String> params, String charset) {
        String json = null;
        try {
            json = new ObjectMapper().writeValueAsString(params);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(), e);
        }

        charset = StringUtils.isEmpty(charset) ? DEFAULT_CHARSET : charset;
        StringEntity entity = new StringEntity(json, charset);
        entity.setContentEncoding(charset);
        entity.setContentType(JSON_CONTENT_TYPE);

        HttpPost method = new HttpPost(url);
        method.setHeader("Content-Type", "application/json;charset=utf-8");
        if (null != headerParam) {
            for (String key : headerParam.keySet()) {
                method.setHeader(key, headerParam.get(key));
            }
        }
        method.setEntity(entity);
        return execute(method, charset);
    }

    /**
     * 以json作为参数发送Http Post请求
     *
     * @param url     请求路径
     * @param params  请求参数 Object类型
     * @param charset 字符集
     * @return
     */
    public static String postJsonObject(String url, Map<String, String> headerParam, Map<String, Object> params, String charset) {
        String jsonBody = null;
        try {
            jsonBody = new ObjectMapper().writeValueAsString(params);
        } catch (JsonProcessingException e) {
            log.error(e.getMessage(), e);
        }
        charset = StringUtils.isEmpty(charset) ? DEFAULT_CHARSET : charset;
        StringEntity entity = new StringEntity(jsonBody, charset);
        entity.setContentEncoding(charset);
        entity.setContentType(JSON_CONTENT_TYPE);

        HttpPost methodPost = new HttpPost(url);
        methodPost.setHeader("Content-Type", "application/json;charset=utf-8");
        if (!CollectionUtils.isEmpty(headerParam)) {
            for (String key : headerParam.keySet()) {
                methodPost.setHeader(key, headerParam.get(key));
            }
        }
        methodPost.setEntity(entity);
        return execute(methodPost, charset);
    }


    public static String execute(HttpUriRequest method, String charset) {
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(method);
            log.info("resphonse ============== " + response.toString());
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                method.abort();
                throw new RuntimeException("HttpClient, error status code :" + statusCode);
            }
            HttpEntity entity = response.getEntity();
            return toString(entity, charset);
        } catch (IOException e) {
            log.error("Http call error: " + e.getMessage(), e);
            return null;
        } finally {
            close(response);
        }
    }

    private static String toString(HttpEntity entity, String charset) throws IOException {
        String result = null;
        if (entity != null) {
            result = EntityUtils.toString(entity, charset);
        }
        EntityUtils.consume(entity);
        return result;
    }

    private static void close(CloseableHttpResponse response) {
        if (response != null) {
            try {
                response.close();
            } catch (IOException e) {
            }
        }
    }
}

